package risoe.syslab.fhnew.hw;

/*
 * Copyright (c) 2012-2014, Technical University of Denmark (DTU)
 * All rights reserved.
 * 
 * The Flexhouse 2.0 platform ("this software") is licensed under the
 * BSD 3-clause license.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *   - Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   - Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *   - Neither the name of DTU nor the names of its contributors may be used to
 *     endorse or promote products derived from this software without specific
 *     prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE TECHNICAL UNIVERSITY OF DENMARK BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

import java.util.ArrayList;
import java.util.HashMap;

import risoe.syslab.fhnew.config.ActuatorConfig;
import risoe.syslab.fhnew.config.HWInterfaceConfig;
import risoe.syslab.fhnew.config.SensorConfig;
import risoe.syslab.fhnew.db.LoggerManager;
import risoe.syslab.fhnew.db.PlatformEventLogger;
import risoe.syslab.model.CompositeMeasurement;

/**
 * Superclass of all HardwareInterfaces.
 * @author M. Svendsen
 */
public abstract class HardwareInterface {
	private String mName;
	private HWModule mHWModule;
	private LoggerManager mLoggerManager;
	protected HashMap<String, CompositeMeasurement> mData;
	private String errorMessage;
	private boolean running;

	/**
	 * Creates a new HardwareInterface using a supplied HWInterfaceConfig
	 * @param hic the HWInterfaceConfig to use
	 */
	protected HardwareInterface(HWInterfaceConfig hic) {
		mData = new HashMap<String,CompositeMeasurement>();
		mName = hic.getName();
		running=false;
	}

	public boolean isRunning() {
	  return running;
	}
	
	public String getErrorMessage() {
	  return errorMessage;
	}
	
	/**
	 * Starts up this HardwareInterface. This method calls the startInterfaceImpl() function which handles startup
	 * of the specific child interface. Should only be called from the HWModule.
	 * @param module
	 * @param loggerManager
	 * @param sensors
	 * @param actuators
	 */
	public boolean startInterface(HWModule module, LoggerManager loggerManager, ArrayList<SensorConfig> sensors, ArrayList<ActuatorConfig> actuators) {
		mHWModule = module;
		mLoggerManager = loggerManager;
		
		try {
			startInterfaceImpl(sensors, actuators);
			running=true;
			errorMessage="";
		} catch (Exception e) {
			mLoggerManager.getPlatformEventLogger().logEvent(getName(), "ERROR", 
					"Exception occured during startup of hardware interface. Message: "+e.getMessage());
			running=false;
			errorMessage=e.getMessage();
			return false;
		}
		return true;
	}

	/**
	 * Stops this particular HardwareInterface. Calls the stopInterfaceImpl() method of the actual interface.
	 */
	//TODO Invalidate all data on stopping
	public void stopInterface() {
		try {
			stopInterfaceImpl();
			running=false;
			errorMessage="";
		} catch (Exception e) {
			mLoggerManager.getPlatformEventLogger().logEvent(getName(), "ERROR", 
					"Exception occured during shutdown of hardware interface. Message: "+e.getMessage());
			running=false;
			errorMessage=e.getMessage();
		}
	}

	/**
	 * Called when this HardwareInterface is started. It is the job of the child interface to correctly map sensors
	 * and actuators in a suitable way for internal use.
	 * @param sensors all the sensors associated with this HardwareInterface
	 * @param actuators all the actuators associated with this HardwareInterface
	 */
	protected abstract void startInterfaceImpl(ArrayList<SensorConfig> sensors, ArrayList<ActuatorConfig> actuators);

	/**
	 * Called when this HardwareInterface should stop. Use this method to clean up any threads/resources that are in use.
	 */
	protected abstract void stopInterfaceImpl();

	/**
	 * @return the name of this HardwareInterface
	 */
	public String getName() {
		return mName;
	}
	
	/**
	 * @return a reference to the PlatformEventLogger
	 */
	public PlatformEventLogger getLogger(){
		return mLoggerManager.getPlatformEventLogger();
	}

	/**
	 * @return whether this interface has successfully connected
	 */
	public abstract boolean isConnected();
	
	/**
	 * Called when the HWModule requests an actuation on this interface
	 * @param actuator for which the actuation must be executed
	 */
	public abstract void applyActuation(Actuator actuator);
	
	/**
	 * Updates the ProcessImage with all the data contained in the "mData" HashMap. Notifies the ControllerManager
	 * of this update asynchronously. Calling this method will clear mData
	 */
	protected final void notifyProcessImage(){
		HashMap<String, CompositeMeasurement> data = mData;
		mData = new HashMap<String, CompositeMeasurement>();
		mHWModule.newData(data);
	}
	
	/**
	 * Attempts a read of the specified sensor on this HardwareInterface. Returns null if not overridden by
	 * a child class.
	 * @param s the sensor to read
	 * @return a CompositeMeasurement representing the reading or null if no such reading can be done
	 */
	public CompositeMeasurement read(Sensor s){
		return null;
	}
}
